﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MSR.LST.Net.Rtp;
using System.Windows.Forms;
using System.Net;
using System.IO;
namespace VideoCall
{
    public partial class FrmVideoCall : Form
    {
        #region Varible
        private static IPEndPoint ep = RtpSession.DefaultEndPoint; // RTP EndPoint
        private RtpSession rtpSession;  //Manages the connection to a multicast address and all the objects related to Rtp
        private RtpParticipant rtpParticipant;
        private RtpSender rtpSenderAudio;
        private RtpSender rtpSenderVideo;
        private RtpSender rtpSenderPicture;
        private RtpSender rtpSenderFile;
        private RtpSender rtpSenderChat;

        private bool IsConfiged = false;
        #endregion

        #region Event
        private void HookRtpParticipantEvents()
        {
            // Add Remove Participant Events
            RtpEvents.RtpParticipantAdded += new RtpEvents.RtpParticipantAddedEventHandler(RtpParticipantAdded);
            RtpEvents.RtpParticipantRemoved += new RtpEvents.RtpParticipantRemovedEventHandler(RtpParticipantRemoved);
        }
        private void HookRtpStreamEvents()
        {
            // Add Remove Stream Events
            RtpEvents.RtpStreamAdded += new RtpEvents.RtpStreamAddedEventHandler(RtpStreamAdded);
            RtpEvents.RtpStreamRemoved += new RtpEvents.RtpStreamRemovedEventHandler(RtpStreamRemoved);
        }
        /// <summary>
        /// Hàm này sẽ được gọi khi có một Client nào đó chạy RTPMulticast
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ea"></param>
        private void RtpParticipantAdded(object sender, RtpEvents.RtpParticipantEventArgs ea)
        {
            //LogRtpMessage = ea.RtpParticipant.Name + " has joined the voice session.";
        }
        /// <summary>
        /// Hàm này được gọi khi có một Client nào đó thoát ra khỏi RTPMulticast
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ea"></param>
        private void RtpParticipantRemoved(object sender, RtpEvents.RtpParticipantEventArgs ea)
        {
            //LogRtpMessage = ea.RtpParticipant.Name + " has left the voice session";
        }
        private void RtpStreamAdded(object sender, RtpEvents.RtpStreamEventArgs ea)
        {
            ea.RtpStream.FrameReceived += new RtpStream.FrameReceivedEventHandler(FrameReceived);
        }
        private void RtpStreamRemoved(object sender, RtpEvents.RtpStreamEventArgs ea)
        {
            ea.RtpStream.FrameReceived -= new RtpStream.FrameReceivedEventHandler(FrameReceived);
        }
        private void UnhookRtpEvents()
        {
            RtpEvents.RtpParticipantAdded -= new RtpEvents.RtpParticipantAddedEventHandler(RtpParticipantAdded);
            RtpEvents.RtpParticipantRemoved -= new RtpEvents.RtpParticipantRemovedEventHandler(RtpParticipantRemoved);
            RtpEvents.RtpStreamAdded -= new RtpEvents.RtpStreamAddedEventHandler(RtpStreamAdded);
            RtpEvents.RtpStreamRemoved -= new RtpEvents.RtpStreamRemovedEventHandler(RtpStreamRemoved);
        }
        private void DisposeRtpSession()
        {
            if (rtpSession != null)
            {
                // Clean up all outstanding objects owned by the RtpSession
                rtpSession.Dispose();
                rtpSession = null;
                rtpSenderAudio = null;
                rtpSenderVideo = null;
                rtpParticipant = null;
            }
        }
        #endregion

        /// <summary>
        /// Cấu hình cho RTPMulticast
        /// Chỉ cấu hình lần đầu tiên
        /// </summary>
        /// <param name="clientID">Phải là mã duy nhất</param>
        /// <param name="multicastGroupIP">Chuỗi IP Multicast</param>
        /// <param name="Port">Port dùng để nhận gửi dữ liệu</param>
        public void RTPMulticast(int clientID, string multicastGroupIP, int Port)
        {
            if (!IsConfiged) IsConfiged = true; //Kiểm tra đã cấu hình lần nào chưa

            // Hook RTP Sesstion
            HookRtpParticipantEvents();
            HookRtpStreamEvents();

            //Cái này là đặt tên để phân biệt giữa các Client với nhau, thích kiểu gì thì xài kiểu đó
            rtpParticipant = new RtpParticipant(clientID.ToString(), clientID + "(Client)");
            ep = new IPEndPoint(IPAddress.Parse(multicastGroupIP), Port);
            rtpSession = new RtpSession(ep, rtpParticipant, true, true);

            //Mỗi dòng dưới đây tương ứng với 1 loại dữ liệu mình cần gửi
            //Cần phải chọn đúng loại để nhận gửi tốt
            rtpSenderAudio = rtpSession.CreateRtpSender(clientID.ToString(), PayloadType.G721, null);
            rtpSenderVideo = rtpSession.CreateRtpSender(clientID.ToString(), PayloadType.dynamicVideo, null);
            rtpSenderPicture = rtpSession.CreateRtpSender(clientID.ToString(), PayloadType.JPEG, null);
            rtpSenderFile = rtpSession.CreateRtpSender(clientID.ToString(), PayloadType.FileTransfer, null);
            rtpSenderChat = rtpSession.CreateRtpSender(clientID.ToString(), PayloadType.Chat, null);

        }
        /// <summary>
        /// Hàm này dùng đóng toàn bộ RTPMulticast
        /// </summary>
        public void Stop()
        {
            UnhookRtpEvents();
            DisposeRtpSession();
        }
        /// <summary>
        /// Bắt đầu nhận dữ liệu lại sau khi đã bấm Pause
        /// </summary>
        public void Resume()
        {
            //HookRtpStreamEvents();
        }
        /// <summary>
        /// Tạm thời dừng nhận dữ liệu
        /// </summary>
        public void Pause()
        {
            RtpEvents.RtpStreamAdded -= new RtpEvents.RtpStreamAddedEventHandler(RtpStreamAdded);
            RtpEvents.RtpStreamRemoved -= new RtpEvents.RtpStreamRemovedEventHandler(RtpStreamRemoved);
        }

        #region Rececive Data
        /// <summary>
        /// Nhận dữ liệu về
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ea"></param>
        private void FrameReceived(object sender, RtpStream.FrameReceivedEventArgs ea)
        {
            Invoke(new MethodInvoker(delegate 
            { 
                //if(rtp

                switch (ea.RtpStream.PayloadType)   //Lúc gửi gói tin thì dùng các hàm gửi phía dưới
                //Tương ứng với cái mình cần gửi
                {
                    case PayloadType.Chat:
                        ReceiveChat(ea.Frame.Buffer);
                        break;
                    case PayloadType.FileTransfer:
                        ReceiveFile(ea.Frame.Buffer);
                        break;
                    case PayloadType.JPEG:
                        break;
                    case PayloadType.G721:
                        ReceiveAudio(ea.Frame.Buffer);
                        break;
                    case PayloadType.dynamicVideo:
                        ReceiveVideo(ea.Frame.Buffer);
                        break;
                    default:
                        break;
                }

            }
            ));
        }
        #endregion

        #region Send Data
        /// <summary>
        /// Hàm này dùng để gửi gói tin Âm thanh
        /// </summary>
        /// <param name="data"></param>
        public void SendAudio(byte[] data)
        {
            rtpSenderAudio.Send(data);
        }
        /// <summary>
        /// Hàm này dùng để gửi gói tin Hình ảnh
        /// </summary>
        /// <param name="data"></param>
        public void SendVideo(byte[] data)
        {
            rtpSenderVideo.Send(data);
        }
        public void SendPicture(byte[] data)
        {
            rtpSenderPicture.Send(data);
        }
        public void SendFile(byte[] data)
        {
            rtpSenderFile.Send(data);
        }
        public void SendChat(byte[] data)
        {
            rtpSenderChat.Send(data);
        }
        #endregion

        public void ReceiveVideo(byte[] data)
        {
            int gr = data[0];
            int tt = data[1];
            if (gr == _groupcurrent)
            {
                Array.Copy(data,2, data, 0, data.Length -2);// data.Skip(2)
                int vt = tt % numberofslider;
                if ((vt == 0 && Current == numberofslider) || vt == Current)
                {
                    ProcessCurrent(data);
                }
                switch (vt)
                {
                    case 1:
                        ProcessVideo(pictureBox1, data);
                        break;
                    case 2:
                        ProcessVideo(pictureBox2, data);
                        break;
                    case 3:
                        ProcessVideo(pictureBox3, data);
                        break;
                    case 4:
                        ProcessVideo(pictureBox4, data);
                        break;
                    case 0:
                        ProcessVideo(pictureBox5, data);
                        break;
                }
            }
        }
        public void ReceiveAudio(byte[] data)
        {
            try
            {
                if (((int)data[0] == this._groupcurrent))
                {
                    if ((int)data[1] != this.YourID)
                        Mic.Play(data);
                    // chỗ này để ghi vào file audio-date time.now.wav
                    Array.Copy(data, 2, data, 0, data.Length - 2);
                    try
                    {
                        if (audio == true)
                            writeraudio.WriteData(data,0,data.Length);
                    }
                    catch (Exception) { }
                    
                }
            }
            catch (Exception)
            {
            }
        }
        public void ReceiveChat(byte[] data)
        {
            AddChat(Encoding.Unicode.GetString(data));
        }
        public void ReceiveFile(byte[] data)
        {

            ///Cấu trúc gói tin gửi
            ///username*IDsender*ipsender*STT-processbarcontrol*tenfile*dodaicuafile*numpart*port
            ///    0        1        2             3               4         5          6      7
            lsbshowchat.Items.Clear();
            for (int i = 0; i < lsbshowchat.Controls.Count * 4; i++)
                lsbshowchat.Items.Add("");
            string[] temp = Encoding.Unicode.GetString(data).Split('|');
            if (temp[0] == "CHAT")
            {
                string[] newdata = temp[1].Split('*');
                if (username != newdata[0])
                {
                    AddChat(newdata[0] + " : " + newdata[4]);
                    // tạo processbarcontrols 
                    ProcessBarSendFile.ProcessBarControl pro = new ProcessBarSendFile.ProcessBarControl();
                    pro.senderID = int.Parse(newdata[1]);

                    pro.SetupReceive(newdata[2], int.Parse(newdata[7]), newdata[4], int.Parse(newdata[5]), int.Parse(newdata[6]), int.Parse(newdata[3]));
                    pro.acceptfile += new ProcessBarSendFile.ProcessBarControl.AcceptFile(pro_acceptfile);
                    pro.openfile += new ProcessBarSendFile.ProcessBarControl.OpenFile(pro_openfile);

                    if (lsbshowchat.Controls.Count == 0)
                        pro.Location = new System.Drawing.Point(0, 20);
                    else
                        pro.Location = new System.Drawing.Point(0, lsbshowchat.Controls[lsbshowchat.Controls.Count - 1].Location.Y + 20);

                    ListFileReceive.Add(pro);
                    lsbshowchat.Controls.Add(pro);
                }
            }
            else// Thằng send file nó không send nữa
            {
                if (temp[0] == "CancelSend")
                {
                    foreach (ProcessBarSendFile.ProcessBarControl pro in ListFileReceive)
                    {
                        if (pro.ID.ToString() == temp[1])
                            pro.Remove();
                    }
                }
                else // Thằng Nhận File nó không nhận nữa
                {
                    //CancelReceive|IDProcessBar|IDSender|this.yourip);
                    //     0             1           2         3
                    if (YourID.ToString() == temp[2])
                    {
                        foreach (ProcessBarSendFile.ProcessBarControl pro in ListFileSend)
                            if (pro.ID.ToString() == temp[1])
                                pro.RemoveSender(temp[3]);
                    }

                }
            }

        }

        void pro_openfile(string data)
        {
            FileInfo fl = new FileInfo(data);
            Invoke(new MethodInvoker(delegate {
                XaReadFiles.ReadFiles rd = new XaReadFiles.ReadFiles();
                webBrowser1.Navigate(rd.LoadDocument(fl.FullName));
            }));
        }

        void pro_acceptfile(string data)
        {
            OnNutDaNhan("AcceptFile|"+yourip+"*"+data);
        }
    }
       
}
